/**
      _                           
     (_)  _ __     ___ _  _    _  
     | | / _` \  / / _`/ _ \ \ /  
     | |/ (_|\ \/ / (_|  __/\ \   
     \ |\__,_ \__/\__,_\___ /\_\  
    /_/                          
                                 
    
    作者：陈霓清
    官网：www.javaex.cn
	说明：vue3 + element-plus 专用版
	版本：1.0.0
    Licences: MIT
*/
import { createVNode, render, h } from 'vue';
import { ElConfigProvider } from 'element-plus';
import zhCn from 'element-plus/es/locale/lang/zh-cn';

;(function() {
    var javaex = function() {
		// 默认属性，可以再扩展
		function defaults(args) {
			var defaults = {};
			return Object.assign(defaults, args);
		}

        var methods = {
			/**
			 * console方法
			 */
			log : function(title, content) {
				if (methods.ifnull(content) == "") {
					content = title;
					title = "log";
				}
				methods.consolePrint(title, content, '#666666');
			},
			info : function(title, content) {
				if (methods.ifnull(content) == "") {
					content = title;
					title = "info";
				}
				methods.consolePrint(title, content, '#1b9aee');
			},
			error : function(title, content) {
				if (methods.ifnull(content) == "") {
					content = title;
					title = "error";
				}
				methods.consolePrint(title, content, '#fa2c19');
			},
			warning : function(title, content) {
				if (methods.ifnull(content) == "") {
					content = title;
					title = "warning";
				}
				methods.consolePrint(title, content, '#FFA10D');
			},
			success : function(title, content) {
				if (methods.ifnull(content) == "") {
					content = title;
					title = "success";
				}
				methods.consolePrint(title, content, '#07c160');
			},
			/**
			 * 控制台输出
			 * @param {*} title 
			 * @param {*} content 
			 * @param {*} color 
			 */
			consolePrint : function(title, content, color) {
				let formattedContent = typeof content === 'object' ? JSON.stringify(content, null, 2) : content;

				if (typeof content === 'object') {
					console.log(
						`%c ${title} %c ${formattedContent} %c`,
						`background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`,
						`padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`,
						'background:transparent'
					);
				} else {
					console.log(
						`%c ${title} %c ${formattedContent} %c`,
						`background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`,
						`border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`,
						'background:transparent'
					);
				}
			},

			/**
             * 动态加载dialog
             * @param {*} Component 组件
             * @param {*} props 
             * @param {*} on 子组件中的defineEmits方法
             * @returns 
             */
			openDialog : function(Component, props = {}, on = {}) {
                const container = document.createElement('div');
                document.body.appendChild(container);
 
                const vnode = createVNode({
					render() {
						return h(ElConfigProvider, { locale: zhCn }, {
							default: () => h(Component, {
								...props,
								...Object.fromEntries(Object.entries(on).map(([key, value]) => [`on${key.charAt(0).toUpperCase()}${key.slice(1)}`, value]))
							})
						});
					}
				});
				
                render(vnode, container);

                return () => {
                    render(null, container);
                    document.body.removeChild(container);
                };
            },

			/**
			 * 定位删除dialog
			 * @param {*} obj 
			 * @param {*} args 
			 */
			deleteDialog : function(obj, args) {
                const target = {
                    content: "",
                    confirmName: "确定",
                    cancelName: "取消",
                    offsetTop: 0,
                    confirm: function() { return true; },
                    cancel: function() { return true; },
                    opend: function() { return true; }
                };
                const settings = Object.assign(target, defaults(args));
 
                // 删除追随弹出层，防止二次弹出
                const existingDialogs = document.querySelectorAll(".javaex-danger-dialog");
                existingDialogs.forEach(dialog => {
                    dialog.parentNode.removeChild(dialog);
                });
 
                const UUID = methods.getUUID(); // 生成随机id
                const offsetTop = parseInt(settings.offsetTop);
                const rect = obj.getBoundingClientRect();
                const left = rect.left + document.documentElement.scrollLeft;
                const top = rect.top + document.documentElement.scrollTop;
                let leftInt = left - 186 + (obj.offsetWidth / 2) + 30;
 
                if ((leftInt + 320) > document.documentElement.clientWidth) {
                    leftInt = document.documentElement.clientWidth - 321;
                }
 
                const topInt = top + obj.offsetHeight - 40 - offsetTop;
 
                // 弹出层代码
                const html = `
                <div id="${UUID}" class="javaex-danger-dialog javaex-win javaex-animated-fadein-up" style="left:${leftInt}px;top:${topInt}px;">
                    <button class="javaex-btn red" id="${UUID}-confirm">${settings.confirmName}</button>
                    <button class="javaex-btn indigo" id="${UUID}-cancel">${settings.cancelName}</button>
                </div>`;
 
                const winId = "javaex-win-" + UUID;
                const contentHtml = `
                <div id="${winId}" class="javaex-win javaex-win-hint javaex-animated-fadein-up">
                    <div class="javaex-error-text">${settings.content}</div>
                    <div class="javaex-tail"></div>
                </div>`;
 
                // 创建一个临时容器，将 html 内容解析为 DOM 元素
                const tempDiv = document.createElement('div');
                tempDiv.innerHTML = html;
 
                // 获取第一个子元素并添加到 body
                const dialogElement = tempDiv.firstElementChild;
                document.body.appendChild(dialogElement);
 
                setTimeout(function() {
                    // 创建一个临时容器，将 contentHtml 解析为 DOM 元素
                    const contentTempDiv = document.createElement('div');
                    contentTempDiv.innerHTML = contentHtml;
 
                    // 获取第一个子元素
                    const contentElement = contentTempDiv.firstElementChild;
 
                    // 找到 UUID 对应的 dialog
                    const dialog = document.getElementById(UUID);
                    if (dialog) {
                        dialog.appendChild(contentElement);
 
                        // 调整位置
                        const topHeight = contentElement.offsetHeight + 5;
                        contentElement.style.top = `-${topHeight}px`;
                    }
                }, 200);
 
                // 绑定 click 事件
                document.getElementById(`${UUID}-confirm`).addEventListener('click', function() {
                    if (settings.confirm() !== false) {
                        document.body.removeChild(dialogElement);
                    }
                });
 
                document.getElementById(`${UUID}-cancel`).addEventListener('click', function() {
                    if (settings.cancel() !== false) {
                        document.body.removeChild(dialogElement);
                    }
                });
 
                // 打开后的回调函数
                settings.opend({});
            },

			/**
			 * @param url      目标文件地址
			 * @param filename 想要保存的文件名称
			 */
			downloadFile : function(url, filename) {
				getBlob(url, function(blob) {
					saveAs(blob, filename);
				});

				/**
				 * 获取 blob
				 * @param  {String} url 目标文件地址
				 * @return {cb} 
				 */
				function getBlob(url, cb) {
					var xhr = new XMLHttpRequest();
					xhr.open('GET', url, true);
					xhr.responseType = 'blob';
					xhr.onload = function() {
							if (xhr.status === 200) {
								cb(xhr.response);
							}
					};
					xhr.send();
				}

				/**
				* 保存
				* @param  {Blob} blob     
				* @param  {String} filename 想要保存的文件名称
				*/
				function saveAs(blob, filename) {
					if (window.navigator.msSaveOrOpenBlob) {
						navigator.msSaveBlob(blob, filename);
					} else {
						var link = document.createElement('a');
						var body = document.querySelector('body');
		
						link.href = window.URL.createObjectURL(blob);
						link.download = filename;
		
						// fix Firefox
						link.style.display = 'none';
						body.appendChild(link);
		
						link.click();
						body.removeChild(link);
		
						window.URL.revokeObjectURL(link.href);
					}
				}
			},

            /**
			 * 生成一个不重复的ID
			 */
			getUUID : function() {
				return Date.now().toString(36) + Math.random().toString(36).substr(3, 3);
			},
			
			/**
			 * 截取指定字符串左边的数据
			 *     str    ：原始字符串
			 *     subkey : 指定的字符串
			 *     flag   : 截取的字符串是否包含key本身（默认不包含）
			 */
			substringLeft : function(str, subkey, flag) {
				if (!methods.ifnull(str) || !methods.ifnull(subkey)) {
					return false;
				}

				let index = str.lastIndexOf(subkey);
				// 如果没找到，直接返回字符串本身
				if (index === -1) {
					return str;
				}
				if (flag) {
					// 包含本身
					return str.substring(0, index) + subkey;
				} else {
					// 不包含本身
					return str.substring(0, index);
				}
			},

			/**
			 * 截取指定字符串右边的数据
			 *     str    ：原始字符串
			 *     subkey : 指定的字符串
			 *     flag   : 截取的字符串是否包含key本身（默认不包含）
			 */
			substringRight : function(str, subkey, flag) {
				if (!methods.ifnull(str) || !methods.ifnull(subkey)) {
					return false;
				}

				let index = str.lastIndexOf(subkey);
				// 如果没找到，直接返回字符串本身
				if (index === -1) {
					return str;
				}
				if (flag) {
					// 包含本身
					return str.substring(index, str.length);
				} else {
					// 不包含本身
					return str.substring(index + subkey.length, str.length);
				}
			},
			
			/**
			 * 获取地址栏参数
			 *   仅适用于不带#的请求路径
			 */
			getParam : function(key) {
				// 正则表达式，用于匹配查询字符串中的键值对
				let reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
				// 截取查询字符串部分，并进行匹配
				let r = window.location.search.substr(1).match(reg);
				if (r != null) {
					return decodeURIComponent(r[2]);
				}
				return null;
			},
			
			/**
			 * 得到系统时间
			 * @param {*} num 
			 * @returns 
			 */
			// 格式化数字，不足10，补0
			add0 : function(num) {
				return (num>=0 && num<=9) ? ("0" + num) : num;
			},
			// 返回今日日期，格式yyyy-MM-dd
			getToday : function() {
				let date = new Date();
				let year = date.getFullYear();
				let month = date.getMonth() + 1;
				let day = date.getDate();
				
				return year + "-" + methods.add0(month) + "-" + methods.add0(day);
			},
			getDay : function() {
				return new Date().getDate();
			},
			getMonth : function() {
				return new Date().getMonth() + 1;
			},
			getYear : function() {
				return new Date().getFullYear();
			},
			// 返回星期：1-7
			getWeek : function() {
				let week = new Date().getDay();
				return week==0 ? 7 : week;
			},
			// 返回当前时间，格式yyyy-MM-dd HH:mm:ss
			now : function() {
				let date = new Date();
				let year = date.getFullYear();
				let month = date.getMonth() + 1;
				let day = date.getDate();
				
				return year + "-" + methods.add0(month) + "-" + methods.add0(day) + " " + methods.add0(date.getHours()) + ":" + methods.add0(date.getMinutes()) + ":" + methods.add0(date.getSeconds());
			},

			/* 
			 * 获得时间差
			 * startTime : 开始时间（时间格式为 yyyy-MM-dd HH:mm:ss 例如：2018-06-21 00:00:00）
			 * endTime : 结束时间（时间格式为 yyyy-MM-dd HH:mm:ss 例如：2018-06-21 00:00:00）
			 * type : 返回精度（second，minute，hour，day）
			 */
			getTimeDiff : function(startTime, endTime, type) {
				//将xxxx-xx-xx的时间格式，转换为 xxxx/xx/xx的格式
				startTime = startTime.replace(/\-/g, "/");
				endTime = endTime.replace(/\-/g, "/");
				//将计算间隔类性字符转换为小写
				type = type.toLowerCase();
				let sTime = new Date(startTime);//开始时间
				let eTime = new Date(endTime);	//结束时间
				
				// 作为除数的数字
				let divNum = 1;
				switch (type) {
					case "second":
						divNum = 1000;
						break;
					case "minute":
						divNum = 1000 * 60;
						break;
					case "hour":
						divNum = 1000 * 3600;
						break;
					case "day":
						divNum = 1000 * 3600 * 24;
						break;
					default:
						break;
				}
				let diff = parseInt((eTime.getTime() - sTime.getTime()) / parseInt(divNum));
				
				return diff > 0 ? diff : 0;
			},
			
			/* 
			 * 获得两个日期之间的周次数
			 * beginDate : 开始日期（时间格式为 yyyy-MM-dd 例如：2021-09-01）
			 * endDate : 结束日期（时间格式为 yyyy-MM-dd 例如：2022-06-28）
			 */
			getWeekDiff : function(beginDate, endDate) {
				// 开始日期的周一
				let beginDateTime = new Date(beginDate);
				let weekFirstDay = new Date(beginDateTime - (beginDateTime.getDay() - 1) * 86400000);
				
				// 计算周次
				let date1 = new Date(weekFirstDay);
				let date2 = new Date(endDate);
				
				let dt1 = date1.getTime();
				let dt2 = date2.getTime();
				// 向上取整
				return Math.ceil(Math.abs(dt1 - dt2) / 1000 / 60 / 60 / 24 / 7);
			},
			
			/**
			 * 格式化时间戳
			 *     timestamp ：时间戳，支持秒和毫秒
			 *     fmt       : 格式化。 例如：yyyy-MM-dd HH:mm:ss
			 */
			dateFormat : function(timestamp, fmt) {
				if (methods.ifnull(timestamp) == "") {
					return "";
				}
				
				let date = null;
				if (/^\d+$/.test(timestamp)) {
					date = (String(timestamp).length>10) ? new Date(Number(timestamp)) : new Date(Number(timestamp) * 1000);
				} else {
					date = new Date(timestamp);
				}
				return doDateFormat(date, fmt);
				
				/**
				 * 时间格式化
				 */
				function doDateFormat(date, fmt) {
					let o = { 
						"M+" : date.getMonth()+1, //月份
						"d+" : date.getDate(), //日
						"h+" : date.getHours()%12 == 0 ? 12 : date.getHours()%12, //小时
						"H+" : date.getHours(), //小时
						"m+" : date.getMinutes(), //分
						"s+" : date.getSeconds(), //秒
						"q+" : Math.floor((date.getMonth()+3)/3), //季度
						"S" : date.getMilliseconds() //毫秒
					}; 
					let week = { 
						"0" : "/u65e5", 
						"1" : "/u4e00", 
						"2" : "/u4e8c", 
						"3" : "/u4e09", 
						"4" : "/u56db", 
						"5" : "/u4e94", 
						"6" : "/u516d"
					};
					if (/(y+)/.test(fmt)) {
						fmt = fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
					} 
					if (/(E+)/.test(fmt)) {
						fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "/u661f/u671f" : "/u5468") : "")+week[date.getDay()+""]);
					} 
					for (var k in o) {
						if (new RegExp("("+ k +")").test(fmt)) {
							fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
						}
					}

					return fmt;
				}
			},
			
			/**
			 * null值替换
			 */
			ifnull : function(str, replaceValue) {
				if (typeof str === "number") {
					return str;
				}
				
				if (replaceValue === undefined) {
					return (!str || str=="undefined") ? "" : str;
				} else {
					return (!str || str=="undefined") ? replaceValue : str;
				}
			},
			
			/**
			 * cookie
			 */
			deleteCookie : function(key) {
				let exp = new Date();
				exp.setTime(exp.getTime() - 1);
				let cval = methods.getCookie(key);
				if (cval!=null) {
					document.cookie = key + "=" + cval + "; path=/; expires=" + exp.toGMTString();
				}
			},
			getCookie : function(key) {
				let strArr = document.cookie.split("; ");
				for (let i=0; i<strArr.length; i++) {
					let temp = strArr[i].split("=");
					if (temp[0]==key) {
						return unescape(temp[1]);
					}
				}
				return "";
			},
			setCookie : function(key, value, time) {
				if (value.constructor === Object || value.constructor === Array) {
					value = JSON.stringify(value);
				}
				if (!time) {
					document.cookie = key + "=" + escape(value) + "; path=/; expires=-1";
				} else {
					let days = parseInt(time);
					let exp = new Date();
					exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);
					document.cookie = key + "=" + escape(value) + "; path=/; expires=" + exp.toGMTString();
				}
			},
			
			/**
			 * localStorage
			 */
			deleteLocalStorage : function(key) {
				if (!!key) {
					localStorage.removeItem(key);
				} else {
					localStorage.clear();
				}
			},
			getLocalStorage : function(key) {
				return localStorage.getItem(key);
			},
			setLocalStorage : function(key, value) {
				if (value.constructor === Object || value.constructor === Array) {
					value = JSON.stringify(value);
				}
				localStorage.setItem(key, value);
			},
			
			/**
			 * sessionStorage
			 */
			deleteSessionStorage : function(key) {
				if (!!key) {
					sessionStorage.removeItem(key);
				} else {
					sessionStorage.clear();
				}
			},
			getSessionStorage : function(key) {
				return sessionStorage.getItem(key);
			},
			setSessionStorage : function(key, value) {
				if (value.constructor === Object || value.constructor === Array) {
					value = JSON.stringify(value);
				}
				sessionStorage.setItem(key, value);
			},
			
			/**
			 * 判断字符串是否是JSON格式
			 */
			isJSON : function(str) {
				if (typeof str === "string") {
					try {
						var obj = JSON.parse(str);
						if (typeof obj === "object" && obj) {
							return true;
						} else {
							return false;
						}
					} catch(e) {
						return false;
					}
				}
				
				return false;
			},
			
			/**
			 * 递归遍历嵌套对象，并替换所有匹配的key
			 * @param obj : 需要遍历的对象
			 * @param searchStringArr : key的字符串数组
			 * @param replaceStringArr : 替换的字符串数组
			 * @returns 返回修改后的对象
			 */
			deepReplaceKeyName : function(obj, searchStringArr, replaceStringArr) {
				switch (typeOf(obj)) {
				case "array":
					for (let i = 0; i<obj.length; i++) {
						obj[i] = methods.deepReplaceKeyName(obj[i], searchStringArr, replaceStringArr);
					}
					break;
				case "object":
					for (let key in obj) {
						let searches, replacements;
						if (searchStringArr instanceof Array && replaceStringArr instanceof Array) {
							if (searchStringArr.length != replaceStringArr.length) {
								continue;
							} else {
								searches = searchStringArr;
								replacements = replaceStringArr;
							}
						} else {
							searches = [searchStringArr];
							replacements = [replaceStringArr];
						}
						let newkey = key;
						for (let i=0; i<searches.length; i++) {
							newkey = newkey.replace(new RegExp(searchStringArr[i], "g"), replaceStringArr[i]);
						}
						obj[newkey] = methods.deepReplaceKeyName(obj[key], searchStringArr, replaceStringArr);
						if (key != newkey) {
							delete obj[key];
						}
					}
					break;
				}
				
				return obj;
				
				/**
				 * 返回对象的真实类型
				 */
				function typeOf(value) {
					let typeofString = typeof value;
					if (typeofString === 'object') {
						if (!value) {
							return "null";
						}
						return (value instanceof Array) ? 'array' : typeofString;
					} else {
						return typeofString;
					}
				};
			},
			
			/**
			 * 获取文件扩展名
			 * @param path 文件路径或文件名称，带后缀
			 * @returns 返回文件扩展名
			 */
			fileExtension : function(path) {
				if (!path || path.substr(0, 4) == 'rtmp') {
					return "";
				}
				path = path.substring(path.lastIndexOf("/") + 1, path.length).split("?")[0].split("#")[0];
				if (path.lastIndexOf('.') > -1) {
					return path.substr(path.lastIndexOf('.') + 1, path.length).toLowerCase();
				}
			}
        };

        return methods;
    };
    
    window.javaex = javaex();
})();